<?php

class CieloBaseRequest extends TXObject {

    public $errors = array();
    protected $data = array();
    protected $fields = array();
    protected $request;
    
    public function run() {
        if (!$this->validate())
            return false;
        
        $data = array();
        foreach ($this->data as $k => $v)
            if (!is_null($v))
                $data[$k] = $v;
        
        $this->request = new CieloRequest(array(
            'curlOptions' => array(
                CURLOPT_POSTFIELDS => $data,
            ),
        ));
        
        return $this->request->run();
    }

    public function validate() {
        $this->errors = array();

        if (!$this->beforeValidate())
            return false;

        $rules = $this->rules();
        foreach ($rules as $options) {
            $attrList = explode(',', array_shift($options));
            $validator = array_shift($options);

            if (isset($options['enable']) && $options['enable'] === false)
                continue;

            $validatorMethod = 'validate' . ucfirst($validator);
            foreach ($attrList as $attr)
                call_user_func_array(array($this, $validatorMethod), array(trim($attr), $options));
        }

        if (!$this->afterValidate())
            return false;

        return empty($this->errors);
    }

    public function beforeValidate() {
        return true;
    }

    public function afterValidate() {
        return true;
    }
    
    public function rules() {
        return array();
    }

    public function addError($attr, $message) {
        if (!isset($this->errors[$attr]))
            $this->errors[$attr] = array();
        $this->errors[$attr][] = strtr($message, array(
            '{attr}' => $attr,
        ));
    }

    protected function validateMatch($attr, $options) {
        if (isset($options['skipOnError']) && $options['skipOnError'] && !empty($this->errors))
            return true;
        if (!isset($this->data[$attr]) || empty($this->data[$attr]))
            return true;
        if (!isset($options['pattern']))
            return true;
        if (!preg_match($options['pattern'], $this->data[$attr]))
            $this->addError($attr, isset($options['message']) ? $options['message'] : '{attr} não é válido.');
        return true;
    }

    protected function validateRequired($attr, $options) {
        if (isset($options['skipOnError']) && $options['skipOnError'] && !empty($this->errors))
            return true;
        if (!isset($this->data[$attr]) || (empty($this->data[$attr]) && $this->data[$attr] !== '0' && $this->data[$attr] !== false))
            $this->addError($attr, isset($options['message']) ? $options['message'] : '{attr} não pode ser vazio.');
        return true;
    }

    protected function validateEmail($attr, $options) {
        if (isset($options['skipOnError']) && $options['skipOnError'] && !empty($this->errors))
            return true;
        if (!isset($this->data[$attr]) || empty($this->data[$attr]))
            return true;
        if (!$this->_validateEmail($this->data[$attr]))
            $this->addError($attr, isset($options['message']) ? $options['message'] : '{attr} não é um email válido.');
        return true;
    }

    protected function _validateEmail($email) {
        return preg_match('/^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/', $email);
    }

    protected function validateUrl($attr, $options) {
        if (isset($options['skipOnError']) && $options['skipOnError'] && !empty($this->errors))
            return true;
        if (!isset($this->data[$attr]) || empty($this->data[$attr]))
            return true;
        if (!$this->_validateUrl($this->data[$attr]))
            $this->addError($attr, isset($options['message']) ? $options['message'] : '{attr} não é uma url válida.');
        return true;
    }

    protected function _validateUrl($url) {
        return preg_match('/^(https?:\/\/)?(([A-Z0-9][A-Z0-9_-]*)(\.[A-Z0-9][A-Z0-9_-]*)+)/i', $url);
    }

    protected function validateLength($attr, $options) {
        if (isset($options['skipOnError']) && $options['skipOnError'] && !empty($this->errors))
            return true;
        if (!isset($this->data[$attr]) || empty($this->data[$attr]))
            return true;
        $len = strlen($this->data[$attr]);
        $min = isset($options['min']) ? $options['min'] : null;
        $max = isset($options['max']) ? $options['max'] : null;
        $params = array(
            '{min}' => $min,
            '{max}' => $max,
        );

        if (empty($min) && $len > $max)
            $this->addError($attr, strtr(isset($options['message']) ? $options['message'] : '{attr} possui um tamanho inválido. Máximo de {max}', $params));
        elseif (empty($max) && $len < $min)
            $this->addError($attr, strtr(isset($options['message']) ? $options['message'] : '{attr} possui um tamanho inválido. Mínimo de {min}', $params));
        elseif ($len < $min || $len > $max)
            $this->addError($attr, strtr(isset($options['message']) ? $options['message'] : '{attr} possui um tamanho inválido. Mínimo de {min} e máximo de {max}', $params));
        else
            return true;
    }

    protected function validateCompare($attr, $options) {
        if (isset($options['skipOnError']) && $options['skipOnError'] && !empty($this->errors))
            return true;
        if (!isset($this->data[$attr]) || empty($this->data[$attr]))
            return true;
        $with = isset($options['with']) ? $options['with'] : null;
        if (empty($with))
            return true;
        if ($this->data[$attr] != $this->data[$with])
            $this->addError($attr, strtr(isset($options['message']) ? $options['message'] : '{attr} e {with} devem ser iguais.', array('{with}' => $this->labelFor($with))));
        return true;
    }
    
    protected function validateIn($attr, $options) {
        if (isset($options['skipOnError']) && $options['skipOnError'] && !empty($this->errors))
            return true;
        if (!isset($this->data[$attr]) || empty($this->data[$attr]))
            return true;
        $range = isset($options['range']) ? $options['range'] : array();
        if (!in_array($this->data[$attr], $range))
            $this->addError($attr, '{attr} não possui um valor válido.');
        return true;
    }

    public function getRequest() {
        return $this->request;
    }
    
    public function getInfo() {
        if ($this->request)
            return $this->request->info;
    }
    
    public function getResponse() {
        if ($this->request)
            return $this->request->response;
    }
    
    public function get($path) {
        $path = explode('/', $path);
        $xml = $this->response;

        if (empty($xml))
            return null;

        while (!empty($path)) {
            $current = array_shift($path);
            if ($current[0] == '@')
                $xml = $xml[substr($current, 1)];
            else
                $xml = $xml->$current;
        }
        
        $xml = (string) $xml;

        return empty($xml) ? null : $xml;
    }
    
    public function __get($name) {
        if (in_array($name, $this->fields))
            if (isset($this->data[$name]))
                return $this->data[$name];
            else
                return null;
        
        return parent::__get($name);
    }
    
    public function __set($name, $value) {
        if (in_array($name, $this->fields))
            return $this->data[$name] = $value;
        
        return parent::__set($name, $value);
    }
    
}
